package cs.ubbcluj.ro.mps.reader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.apache.log4j.Logger;

import cs.ubbcluj.ro.common.CommonTools;
import cs.ubbcluj.ro.mps.bridge.interfaces.MpsImpInterface;
import cs.ubbcluj.ro.mps.data.MpsImpl;
import cs.ubbcluj.ro.mps.data.interfaces.Mps;
import cs.ubbcluj.ro.mps.states.BoundsState;
import cs.ubbcluj.ro.mps.states.ConstrainsState;
import cs.ubbcluj.ro.mps.states.ErrorState;
import cs.ubbcluj.ro.mps.states.KeyWordState;
import cs.ubbcluj.ro.mps.states.NameState;
import cs.ubbcluj.ro.mps.states.RangesState;
import cs.ubbcluj.ro.mps.states.RhsState;
import cs.ubbcluj.ro.mps.states.VariablesState;
import cs.ubbcluj.ro.mps.states.interfaces.State;

/**
 * The MPS parser - finite state machine
 * 
 * @author avadas
 * @version 1.0
 */
public strictfp class MpsParser {

    /** The logger */
    private final Logger LOG = CommonTools.getLogger(MpsParser.class);

    /** The MPS input stream */
    private MpsInputStream inputStream;

    /** Start state */
    private State startState;
    
    MpsImpInterface imp;

    /**
     * Constructor
     * 
     * @param filePath
     *            the path to the mps file
     */
    public MpsParser(MpsImpInterface mpsImp) {
    	this.imp=mpsImp;
    	initialize();
    }

    /**
     * Parses an MPS file
     * 
     * @param filePath
     *            the path of the file
     * @return the resulted Mps object
     * @throws IOException
     *             see {@link IOException}
     */
    public Mps parse(final String filePath) throws IOException {

	Mps resultMps = null;

	this.inputStream = new MpsInputStream(new FileInputStream(new File(
		filePath)));

	resultMps = new MpsImpl(imp);
	imp.setTheMps(resultMps);

	this.LOG.info(" START PARSING FILE: " + filePath + "\n");

	State newState = this.startState.nextState(this.inputStream, resultMps);
	while (newState != null) {
	    newState = newState.nextState(this.inputStream, resultMps);
	}

	return resultMps;
    }

    /**
     * Initializes the states
     */
    private void initialize() {

	final State errorState = new ErrorState(null, null);

	final State endDataState = new KeyWordState(null, errorState, "ENDATA");

	final State boundsState = new BoundsState(endDataState, errorState,
		null);

	final State boundsKeywordState = new KeyWordState(boundsState,
		errorState, "BOUNDS");

	final State rangesState = new RangesState(endDataState,
		boundsKeywordState, errorState);

	final State rangesKeywordState = new KeyWordState(rangesState,
		errorState, "RANGES");

	final State rhsSectionState = new RhsState(endDataState,
		rangesKeywordState, boundsKeywordState, errorState);

	final State rhsKeyWordState = new KeyWordState(rhsSectionState,
		errorState, "RHS");

	final State variableState = new VariablesState(rhsKeyWordState,
		errorState);

	final State columnsKeyWordState = new KeyWordState(variableState,
		errorState, "COLUMNS");

	final State constrainsState = new ConstrainsState(columnsKeyWordState,
		errorState);

	final State rowsKeyWordState = new KeyWordState(constrainsState,
		errorState, "ROWS");

	final State nameState = new NameState(rowsKeyWordState, errorState);

	this.startState = nameState;
    }
}
